package com.uni.crawl.job;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.uni.crawl.common.enums.crawl.CrawlMonitorTypeEnum;
import com.uni.crawl.common.enums.crawl.CrawlNotifyStatusEnum;
import com.uni.crawl.common.enums.crawl.CrawlQueueUrlTypeEnum;
import com.uni.crawl.common.enums.crawl.DictTypeEnum;
import com.uni.crawl.config.support.EmailConfig;
import com.uni.crawl.model.entity.SysDict;
import com.uni.crawl.model.entity.crawl.CrawlMonitor;
import com.uni.crawl.model.entity.crawl.CrawlQueue;
import com.uni.crawl.service.SysDictService;
import com.uni.crawl.service.crawl.CrawlMonitorService;
import com.uni.crawl.service.crawl.CrawlQueueService;
import com.uni.crawl.service.support.EmailService;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 爬虫监控任务
 */
@Component
@Slf4j
@AllArgsConstructor
public class CrawlMonitorJob extends AbstractJob {

    private final CrawlQueueService crawlQueueService;
    private final CrawlMonitorService crawlMonitorService;
    private final EmailConfig emailConfig;
    private final EmailService emailService;
    private final SysDictService sysDictService;

    @XxlJob("crawlMonitorJob")
    @Override
    public ReturnT<String> handle() {
        LambdaQueryWrapper<SysDict> dictWp = Wrappers.lambdaQuery();
        dictWp.eq(SysDict::getTypeCode, DictTypeEnum.CRAWL_MONITOR.getType());
        dictWp.eq(SysDict::getName, CrawlMonitorTypeEnum.QUEUE.getType());
        dictWp.eq(SysDict::getStatus, 1);

        List<SysDict> monitorDicts = sysDictService.list(dictWp);
        if (CollUtil.isEmpty(monitorDicts)) {
            return success();
        }

        LambdaQueryWrapper<CrawlQueue> queueWp = Wrappers.lambdaQuery();
        // 最近1分钟队列情况监控
        queueWp.ge(CrawlQueue::getCreateTime, LocalDateTime.now().minusMinutes(1L));
        queueWp.eq(CrawlQueue::getUrlType, CrawlQueueUrlTypeEnum.LIST.getType());
        List<CrawlQueue> queues = crawlQueueService.list(queueWp);
        Set<String> keywords = monitorDicts.stream().map(SysDict::getValue).collect(Collectors.toSet());

        List<MonitorQueueDto> hitQueues = new ArrayList<>();
        for (CrawlQueue queue : queues) {
            if (crawlMonitorService.exists(queue.getUrlMd5())) {
                continue;
            }
            for (String keyword : keywords) {
                boolean hit = queue.getTitle().contains(keyword);
                if (hit) {
                    MonitorQueueDto dto = new MonitorQueueDto();
                    dto.setCrawlQueue(queue);
                    dto.setKeyword(keyword);
                    hitQueues.add(dto);
                }
            }
        }

        if (CollUtil.isNotEmpty(hitQueues)) {
            CrawlMonitor monitor = buildContent(hitQueues);

            LambdaQueryWrapper<SysDict> rcvDictWp = Wrappers.lambdaQuery();
            rcvDictWp.eq(SysDict::getTypeCode, DictTypeEnum.MONITOR_NOTIFY_EMAIL.getType());
            rcvDictWp.eq(SysDict::getStatus, 1);
            for (SysDict rcvDict : sysDictService.list(rcvDictWp)) {
                monitor.setToUser(rcvDict.getName());
                crawlMonitorService.save(monitor);

                try {
                    emailService.sendSimpleMail(rcvDict.getName(), monitor.getNotifyTitle(), monitor.getNotifyContent());
                    monitor.setNotifyStatus(CrawlNotifyStatusEnum.OK.getStatus());
                } catch (Exception e) {
                    monitor.setNotifyStatus(CrawlNotifyStatusEnum.ERR.getStatus());
                }

                monitor.setUpdateTime(LocalDateTime.now());
                crawlMonitorService.updateById(monitor);
            }
        }

        return success();
    }

    private CrawlMonitor buildContent(List<MonitorQueueDto> hitQueues) {
        CrawlMonitor monitor = new CrawlMonitor();
        monitor.setFromUser(emailConfig.getFrom());
        monitor.setNotifyTitle(StrUtil.format("uni-crawl监控到{}条抓取结果", hitQueues.size()));
        monitor.setUrlMd5s(hitQueues.stream().map(item -> item.crawlQueue.getUrlMd5()).collect(Collectors.toList()));
        monitor.setNotifyStatus(CrawlNotifyStatusEnum.INIT.getStatus());
        monitor.setCreateTime(LocalDateTime.now());

        StringBuilder sb = new StringBuilder();
        sb.append("Hi:\n");
        sb.append(StrUtil.format("    以下是监控到的{}条结果明细\n"));
        for (int i = 0; i < hitQueues.size(); i++) {
            MonitorQueueDto hitQueue = hitQueues.get(i);
            sb.append(StrUtil.format("\n【结果{}】\n", i + 1));
            sb.append("监控关键词: ").append(hitQueue.keyword).append("\n");
            sb.append("来源标题: ").append(hitQueue.crawlQueue.getTitle()).append("\n");
            sb.append("来源URL: ").append(hitQueue.crawlQueue.getUrl()).append("\n");
        }
        monitor.setNotifyContent(sb.toString());

        return monitor;
    }

    @Data
    private static class MonitorQueueDto {
        private CrawlQueue crawlQueue;
        private String keyword;
    }
}
